package com.dynamic.mybatis.web.controller;


import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.dynamic.mybatis.core.enums.Alert;
import com.dynamic.mybatis.core.enums.CommandType;
import com.dynamic.mybatis.core.metadata.DynamicMappedStatement;
import com.dynamic.mybatis.core.metadata.DynamicMappedStatementMixedResult;
import com.dynamic.mybatis.core.metadata.DynamicPage;
import com.dynamic.mybatis.core.metadata.MappedStatementMetaField;
import com.dynamic.mybatis.core.parser.xml.DynamicMappedStatementParser;
import com.dynamic.mybatis.core.session.DynamicSqlSessionTemplate;
import com.dynamic.mybatis.core.toolkit.BeanUtils;
import com.dynamic.mybatis.core.toolkit.StringUtils;
import com.dynamic.mybatis.core.toolkit.TreeUtil;
import com.dynamic.mybatis.web.vo.DynamicMappedStatementVo;
import com.dynamic.mybatis.web.vo.MappedStatementQueryVo;
import com.dynamic.mybatis.web.vo.MappedStatementValidateVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RequestMapping("/dms/")
@RestController
public class MappedStatementController {
    Logger logger = LoggerFactory.getLogger(MappedStatementController.class);

    @Autowired
    private DynamicSqlSessionTemplate sqlSessionTemplate;


    @PostMapping("/generateParser")
    public DynamicMappedStatementMixedResult generateParser(@RequestBody MappedStatementValidateVo validate) {
        DynamicMappedStatementMixedResult result = null;
        DynamicMappedStatementParser mappedStatementParser =  sqlSessionTemplate.getDynamicMappedStatementHelper().getMappedStatementParser();
        //自定义SQL
        if(StringUtils.isNotBlank(validate.getSqlStatement())){
            result  = mappedStatementParser.validate(validate.getNamespace(),validate.getDataSourceCodes(),validate.getSqlStatement(),validate.getParses());
            //单表
        }else if(CollectionUtils.isNotEmpty(validate.getTables())){
            result  = mappedStatementParser.validate(validate.getNamespace(),validate.getDataSourceCodes(),validate.getTables(),validate.getMethods(),validate.getParses());
        }
        //处理已经合并的数据
        DynamicMappedStatementMixedResult   result1 = mappedStatementParser.merge(validate.getNamespace(),result.getSqlStatement(),BeanUtils.serializeCopy(result.getParserResults()));
        return resultHandle(result,result1,validate.getOperate());
    }

    @PostMapping("/test")
    public DynamicMappedStatementMixedResult test(@RequestBody MappedStatementValidateVo validate){
        //校验
        DynamicMappedStatementMixedResult result = generateParser(BeanUtils.serializeCopy(validate));
        DynamicMappedStatementMixedResult result1 = null;
        if(result.getStatus() != null && result.getStatus() != Alert.StandardAlert.error){
            //测试执行
            DynamicMappedStatementParser mappedStatementParser =   sqlSessionTemplate.getDynamicMappedStatementHelper().getMappedStatementParser();
            result1 =  mappedStatementParser.parseValidateExecute(Boolean.TRUE,validate.getNamespace(),validate.getSqlStatement(),BeanUtils.serializeCopy(result.getParserResults()));
        }
        if(result1 != null && result != null){
            result1.setParserResults(result.getParserResults());
        }
        return resultHandle(result,result1,validate.getOperate());
    }

    @PostMapping("/submit")
    public DynamicMappedStatementMixedResult submit(@RequestBody MappedStatementValidateVo validate){
        DynamicMappedStatementParser mappedStatementParser = sqlSessionTemplate.getDynamicMappedStatementHelper().getMappedStatementParser();
        //测试 序列化深拷贝
        DynamicMappedStatementMixedResult result =  test(BeanUtils.serializeCopy(validate));
        DynamicMappedStatementMixedResult result1 = null;
       //测试成功处理
       if(result.getStatus() != null && result.getStatus() != Alert.StandardAlert.error){
           //解析序列化深拷贝
           result1 = mappedStatementParser.parseValidateExecute(Boolean.FALSE,validate.getNamespace(),validate.getSqlStatement(),BeanUtils.serializeCopy(result.getParserResults()));
       }
       return resultHandle(result,result1,validate.getOperate());
    }


    private DynamicMappedStatementMixedResult resultHandle(DynamicMappedStatementMixedResult result,DynamicMappedStatementMixedResult result1,String operate){
        if(result == null){
            result = new DynamicMappedStatementMixedResult();
        }else if(result1 != null) {
            if (result1.getStatus() == Alert.StandardAlert.success) {
                result1.setStatus(result.getStatus());
                result1.setMessage(result.getMessage());
            }
            result = result1;
        }
        result.setOperate(operate);
        return result;
    }

    @RequestMapping("/page")
    public DynamicPage page(MappedStatementQueryVo queryVo){
        List<DynamicMappedStatement> dmsList = filter(queryVo).skip((queryVo.getPageNumber() - 1) * queryVo.getPageSize()).limit(queryVo.getPageSize()).collect(Collectors.toList());
        List<DynamicMappedStatementVo> dmsVoList =   pageTransport(dmsList);
        TreeUtil.setTree(dmsVoList,0,"treeParentId","treeId","children");
        dmsVoList =  TreeUtil.toArray(dmsVoList,"children");
        long total = filter(queryVo).count();
        return queryVo.result(dmsVoList,total);
    }

    private List<DynamicMappedStatementVo> pageTransport(List<DynamicMappedStatement> dmsList){
        return   dmsList.stream().map(d -> {
            DynamicMappedStatementVo dmsVo = new DynamicMappedStatementVo();
            BeanUtils.copy(d,dmsVo);
            if(CollectionUtils.isNotEmpty(d.getChildren())){
                List<DynamicMappedStatement> children =  dmsVo.getChildren();
                dmsVo.setChildren(new ArrayList<>());
                dmsVo.getChildren().addAll(pageTransport(children));
            }
            return dmsVo;
        }).collect(Collectors.toList());
    }


    @RequestMapping("/getById")
    public DynamicMappedStatementMixedResult getById(String id){
        return  sqlSessionTemplate.getDynamicMappedStatementHelper().getMappedStatementParser().parseMappedStatement(id);
    }

    private Stream<DynamicMappedStatement> filter(MappedStatementQueryVo queryVo){
       return filter(sqlSessionTemplate.getDynamicMappedStatementHelper().mappedStatementValues(),true,queryVo);
    }

    private Stream<DynamicMappedStatement> filter(Collection<DynamicMappedStatement> dmsList,boolean rootNode,MappedStatementQueryVo queryVo){

        return dmsList.stream().filter( d ->  {
            if(!(d instanceof DynamicMappedStatement)){
                return Boolean.FALSE;
            }
            boolean flag = Boolean.TRUE;
            if(rootNode && !StringUtils.isBlank(d.getParentId())){
                flag = Boolean.FALSE;
            }if(StringUtils.isNotBlank(queryVo.getNamespace()) && !Objects.equals(d.getNamespace(),queryVo.getNamespace())){
                flag = Boolean.FALSE;
            }else if(StringUtils.isNotBlank(queryVo.getShortId()) && !Objects.equals(d.getShortId(),queryVo.getShortId())){
                flag = Boolean.FALSE;
            }else if(StringUtils.isNotBlank(queryVo.getCommandType()) && !Objects.equals(d.getCommandType().commandType(),queryVo.getCommandType())){
                flag = Boolean.FALSE;
            }else if(StringUtils.isNotBlank(queryVo.getReturnType()) && !Objects.equals(d.getReturnType().returnType(),queryVo.getReturnType())){
                flag = Boolean.FALSE;
            }else if(StringUtils.isNotBlank(queryVo.getMethod()) && !Objects.equals(d.getMethod().method(),queryVo.getMethod())){
                flag = Boolean.FALSE;
            }
            if(!flag && CollectionUtils.isNotEmpty(d.getChildren())){
                flag = filter(d.getChildren(),false,queryVo).findFirst().isPresent();
            }
            return flag;
        });
    }
}